
using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Media.Imaging;
using System.Windows.Threading;
using System.ComponentModel;

namespace Tanks
{

    public class Tank
    {
        int id ;//уникальный идентификатор танка
        public int ID
        {
            get { return id; }
        }


        Path path;//фигура нашего танка      

        int frags=0;//количетсво подбитых танков
        public int Frags
        {
            get { return frags; }
            set
            { 
                frags = value;
                refresh_frags();
            }
        }

        string name;//имя вводимое игроком
        public string Name
        {
            get { return name; }
            set
            {
                name = value;
                refresh_damage();
            }
        }

        Color team;//принадлежность танка к команде (команды различаются по цвету)
        public Color Team
        {
            get { return team; }
        }

        Point position;//позиция танка на экране
        public Point Position
        {
            get { return position; }
            set { position = value; }
        }

        Direction course;//текущее направление движения
        public Direction Course
        {
            get { return course; }
            set { course = value; }
        }

        int rate=250;//скорострельность
        public int Rate 
        {
            get { return rate; }
        }

        int speed_bullet=5;//скорость полета пули
        public int Speed_bullet
        {
            get { return speed_bullet; }
        }

        int speed_tank=8;//скорость танка
        public int Speed_tank
        {
            get { return speed_tank; }
        }

        int invisibility = 1;//видимость нашего танка на экране
        public int Invisibility
        {
            get { return invisibility; }
        }

        int damage = 0;//процент повреждений
        public int Damage
        {
            get { return damage; }
        }

        public bool Can_bonus_gen { get; set; }//

        public Tank(Color t, Point pos, Direction c,int ident)//инициализирыет наш танк командой, позицией на экране и направлнеием движения
        {
            team = t;
            position = pos;
            course = c;
            if (ident == 0)
            {
                Random r = new Random();
                id = r.Next(1, 1000);
            }
            else
                id = ident;
            create();
        }

        public Tank()
        {
            team = Colors.Blue;
            position = new Point(200, 200);
            course = Direction.Up;
            Random r = new Random();
            id = r.Next(1, 1000);
            create();
        }

        public Tank(Tank t)
        {
            team = t.team;
            position = t.position;
            course = t.course;
            id = t.id;
            create();
        }



        void create()// первоначальная прорисовка танка
        {
            path = new Path();
            GeometryGroup group = new GeometryGroup();
            RectangleGeometry rect1 = new RectangleGeometry();
            rect1.Rect = new Rect(-4, 6, 15, 50);
            rect1.RadiusX = 10;
            rect1.RadiusY = 5;
            EllipseGeometry ellipse = new EllipseGeometry();
            ellipse.Center = new Point(26, 34);
            ellipse.RadiusX = 15;
            ellipse.RadiusY = 15;
            RectangleGeometry rect2 = new RectangleGeometry();
            rect2.Rect = new Rect(41, 6, 15, 50);
            rect2.RadiusX = 10;
            rect2.RadiusY = 5;
            RectangleGeometry rect3 = new RectangleGeometry();
            rect3.Rect = new Rect(22, -4, 8, 24);
            rect3.RadiusX = 10;
            rect3.RadiusY = 1;
            group.Children.Add(rect1);
            group.Children.Add(ellipse);
            group.Children.Add(rect2);
            group.Children.Add(rect3);
            group.FillRule = FillRule.EvenOdd;
            path.Height = 62;
            path.Width = 62;
            path.Stroke = new SolidColorBrush(Colors.Black);
            path.Data = group;
            ImageBrush im_br = new ImageBrush();
            if (team == Colors.Blue)
                im_br.ImageSource = new BitmapImage(new Uri("/Tanks;component/Images/камуфляж_blue.png", UriKind.Relative));
            else
                im_br.ImageSource = new BitmapImage(new Uri("/Tanks;component/Images/камуфляж_red.png", UriKind.Relative));
            path.Fill = im_br;
            ((App)Application.Current).Main_canvas.Children.Add(path);

            draw(true, true, true, true);
        }


       public void draw(bool top_ch, bool left_ch, bool invisibility_ch, bool course_ch)//прорисовка танка, вызванная изменениями его координаты,повреждений или направлением движения
        {
            if (top_ch)
                Canvas.SetTop(path, position.Y);
            if (left_ch)
                Canvas.SetLeft(path, position.X);
            if (invisibility_ch)
                path.Opacity = invisibility;
            if (course_ch)
                switch (course)
                {
                    case Direction.Up:
                        {
                            path.Projection = prepare_pojection(0);
                            break;
                        }
                    case Direction.Right:
                        {
                            path.Projection = prepare_pojection(90);
                            break;
                        }
                    case Direction.Down:
                        {
                            path.Projection = prepare_pojection(180);
                            break;
                        }
                    case Direction.Left:
                        {
                            path.Projection = prepare_pojection(270);
                            break;
                        }
                }
        }

        PlaneProjection prepare_pojection(int angle)// функция возвращает объект преобразования, используя угол поворота 
        {
            PlaneProjection pl = new PlaneProjection();
            pl.CenterOfRotationX = 0.5;
            pl.CenterOfRotationY = 0.5;
            pl.CenterOfRotationZ = 0.5;
            pl.RotationZ = 360 - angle;
            return pl;
        }

        CompositeTransform prepare_transform(int angle)// функция возвращает объект преобразования, используя угол поворота 
        {
            CompositeTransform ct = new CompositeTransform();
            ct.Rotation = angle;
            return ct;
        }

        public void move_up()//движение вперед
        {
            double top;
            top = Canvas.GetTop(path);
            if (top > 4+speed_tank)
                position.Y -= speed_tank;
            else
                position.Y = 4;
            define_wall_point();
            define_tank_point();
            analyze_bonus_point();
            draw(true, false, false, false);
        }

        public void move_down()//движение назад
        {
            double top;
            top = Canvas.GetTop(path);
            if (top < 530 - speed_tank)//455
                position.Y += speed_tank;
            else
                position.Y = 530;//460
            define_wall_point();
            define_tank_point();
            analyze_bonus_point();
            draw(true, false, false, false);
        }

        public void move_left()//движение влево
        {
            double left;
            left = Canvas.GetLeft(path);
            if (left > 4 + speed_tank)
                position.X -= speed_tank;
            else
                position.X = 4;
            define_wall_point();
            define_tank_point();
            analyze_bonus_point();
            draw(false, true, false, false);
        }

        public void move_right()//движение вправо
        {
            double left;
            left = Canvas.GetLeft(path);
            if (left < 680 - speed_tank)//672
                position.X += speed_tank;
            else
                position.X = 680;//672
            define_wall_point();
            define_tank_point();
            analyze_bonus_point();
            draw(false, true, false, false);
        }

        public void rotate_up()//поворот вперед
        {
            if (course == Direction.Down)//ввод поправок при повороте
            {
                position.X += 10;
                position.Y += 10;
                course = Direction.Up;
                draw(true, true, false, true);
                return;
            }
            if (course == Direction.Left)
            {
                position.Y += 10;
                course = Direction.Up;
                draw(true, false, false, true);
                return;
            }
            if (course == Direction.Right)
            {
                position.X += 10;
                course = Direction.Up;
                draw(false, true, false, true);
                return;
            }
            
            course = Direction.Up;
            draw(false, false, false, true);
        }

        public void rotate_down()//поворот назад
        {
            if (course == Direction.Up)
            {
                position.X -= 10;
                position.Y -= 10;
                course = Direction.Down;
                draw(true, true, false, true);
                return;
            }
            if (course == Direction.Right)
            {
                position.Y -= 10;
                course = Direction.Down;
                draw(true, false, false, true);
                return;
            }
            if (course == Direction.Left)
            {
                position.X -= 10;
                course = Direction.Down;
                draw(false, true, false, true);
                return;
            }
            course = Direction.Down;
            draw(false, false, false, true);
        }

        public void rotate_left()//поворот налево
        {
            if (course == Direction.Right)
            {
                position.Y -= 10;
                position.X += 10;
                course = Direction.Left;
                draw(true, true, false, true);
                return;
            } 
            if (course == Direction.Up)
            {
                position.Y -= 10;
                course = Direction.Left;
                draw(true, false, false, true);
                return;
            }
            if (course == Direction.Down)
            {
                position.X += 10;
                course = Direction.Left;
                draw(false, true, false, true);
                return;
            }
            course = Direction.Left;
            draw(false, false, false, true);
        }

        public void rotate_right()//поворот направо
        {
            if (course == Direction.Left)
            {
                position.Y += 10;
                position.X -= 10;
                course = Direction.Right;
                draw(true, true, false, true);
                return;
            }
            if (course == Direction.Down)
            {
                position.Y += 10;
                course = Direction.Right;
                draw(true, false, false, true);
                return;
            }
            if (course == Direction.Up)
            {
                position.X -= 10;
                course = Direction.Right;
                draw(false, true, false, true);
                return;
            }
            course = Direction.Right;
            draw(false, false, false, true);
        }

        bool define_wall_point()//функция анализирует, не наткнулся ли танчик при движении на стенку
        {
            foreach (Wall w in ((App)Application.Current).map.List_of_walls)
            {
                if (course == Direction.Up)
                    if (position.X+55 > w.Left_up.X && position.X < w.Right_down.X && position.Y+5 > w.Left_up.Y && position.Y < w.Right_down.Y+5)
                    {
                        position.Y = w.Right_down.Y+5;
                        return true;
                    }
                if (course == Direction.Right)
                    if (position.X > w.Left_up.X - 67 && position.X < w.Right_down.X - 67 && position.Y+55 > w.Left_up.Y && position.Y-2 < w.Right_down.Y)
                    {
                        position.X = w.Left_up.X - 67;
                        return true;
                    }
                if (course == Direction.Down)
                    if (position.X+67 > w.Left_up.X && position.X+5 < w.Right_down.X && position.Y > w.Left_up.Y - 67 && position.Y < w.Right_down.Y - 67)
                    {
                        position.Y = w.Left_up.Y - 67;
                        return true;
                    }
                if (course == Direction.Left)
                    if (position.X > w.Left_up.X + 5 && position.X < w.Right_down.X + 5 && position.Y+65 > w.Left_up.Y && position.Y+5 < w.Right_down.Y)
                    {
                        position.X = w.Right_down.X + 5;
                        return true;
                    }
            }
            return false;
        }

        void analyze_bonus_point()//функция анализирует, не подобрал ли танчик бонус
        {
            if (course == Direction.Up)
                if (position.X + 55 > 350 && position.X < 400 && position.Y + 5 > 250 && position.Y-5 < 300)
                {
                    if (((App)Application.Current).bonus != null)
                        apply_bonus(((App)Application.Current).bonus.Type);
                }
            if (course == Direction.Right)
                if (position.X+67 > 350 && position.X < 400 && position.Y + 55 > 250 && position.Y - 2 < 300)
                {
                    if (((App)Application.Current).bonus != null)
                        apply_bonus(((App)Application.Current).bonus.Type);
                }
            if (course == Direction.Down)
                if (position.X + 67 > 350 && position.X + 5 < 400 && position.Y+67 > 250 && position.Y+67 < 300)
                {
                    if (((App)Application.Current).bonus != null)
                        apply_bonus(((App)Application.Current).bonus.Type);
                }
            if (course == Direction.Left)
                if (position.X-5 > 350 && position.X-5 < 400 && position.Y + 65 > 250 && position.Y + 5 < 300)
                {
                    if (((App)Application.Current).bonus != null)
                        apply_bonus(((App)Application.Current).bonus.Type);
                }
           
        }

        bool define_tank_point()//определяет, принадлежит ли точка какому-нибудь танку
        {
            foreach (Tank t in ((App)Application.Current).Tanks)
            {
                if (this == t)
                    continue;
                if (course == Direction.Up)
                {
                    if (position.X + 62 > t.position.X && position.X < t.position.X+71 && position.Y > t.position.Y && position.Y - 71 < t.position.Y)
                    {
                        position.Y = t.position.Y + 71;
                        return true;
                    }
                }
                if (course == Direction.Right)
                {
                    if (position.X + 71 > t.position.X && position.X < t.position.X+67 && position.Y+71 > t.position.Y && position.Y  < t.position.Y+62)
                    {
                        position.X = t.position.X - 71;
                        return true;
                    }
                }
                if (course == Direction.Down)
                {
                    if (position.X + 71 > t.position.X && position.X < t.position.X+71 && position.Y+71 > t.position.Y && position.Y < t.position.Y+71)
                    {
                        position.Y = t.position.Y-71;
                        return true;
                    }
                }
                if (course == Direction.Left)
                {
                    if (position.X > t.position.X && position.X < t.position.X+71 && position.Y+62 > t.position.Y && position.Y  < t.position.Y+71)
                    {
                        position.X = t.position.X + 71;
                        return true;
                    }
                }
            }
            return false;
        }

        void apply_bonus(BonusType b)//распознает передаваемый тип бонуса и вызывает соответствующую функцию
        {
            ((App)Application.Current).Main_canvas.Children.Remove(((App)Application.Current).bonus.Rect);
            ((App)Application.Current).bonus = null;
            if (b == BonusType.Rate)
            {
                apply_rate_bonus();
                return;
            }
            if (b == BonusType.Speed_tank)
            {
                apply_speed_tank_bonus();
                return;
            }
            if (b == BonusType.Speed_bullet)
            {
                apply_speed_bullet_bonus();
                return;
            }
            if (b == BonusType.Invisibility)
            {
                apply_invisibility_bonus();
                return;
            }
        }


         void apply_rate_bonus()//бонус увеличивает скорострельность
        {
            rate = 100;
            DispatcherTimer dt = new DispatcherTimer();
            dt.Interval = new TimeSpan(0, 0, 0, 10);
            dt.Tick += new EventHandler(cancel_rate_bonus);
            dt.Start();
        }
         void apply_speed_tank_bonus()//бонус увеличивает скорсть танка
        {
            speed_tank = 20;
            DispatcherTimer dt = new DispatcherTimer();
            dt.Interval = new TimeSpan(0, 0, 0, 10);
            dt.Tick += new EventHandler(cancel_speed_tank_bonus);
            dt.Start();
        }
        public void apply_speed_bullet_bonus()//бонус увеличивает скорость пули
        {
            speed_bullet = 15;
            DispatcherTimer dt = new DispatcherTimer();
            dt.Interval = new TimeSpan(0, 0, 0, 10);
            dt.Tick += new EventHandler(cancel_speed_bullet_bonus);
            dt.Start();
        }
        void apply_invisibility_bonus()//бонус делает танчик невидимым для врагов
        {
            invisibility = 0;
            //draw(false,false,true,false);
            DispatcherTimer dt = new DispatcherTimer();
            dt.Interval = new TimeSpan(0, 0, 0, 10);
            dt.Tick += new EventHandler(cancel_invisibility_bonus);
            dt.Start();            
        }

        public void make_enemy_invisible()///функция вызывается из клинтского приложения для того, что бы сделать танчик врага невидимым
                                          ///в случае, если тот подберет бонус невидимости
        {
            invisibility = 0;
            draw(false, false, true, false);
            DispatcherTimer dt = new DispatcherTimer();
            dt.Interval = new TimeSpan(0, 0, 0, 10);
            dt.Tick += new EventHandler(cancel_invisibility_bonus);
            dt.Start(); 
        }

        void cancel_rate_bonus(object sender, EventArgs e)
        {
            rate = 250;
            DispatcherTimer dt = (DispatcherTimer)sender;
            dt.Stop();
        }

        void cancel_speed_tank_bonus(object sender, EventArgs e)
        {
            speed_tank = 8;
            DispatcherTimer dt = (DispatcherTimer)sender;
            dt.Stop();
        }

        void cancel_speed_bullet_bonus(object sender, EventArgs e)
        {
            speed_bullet = 5;
            DispatcherTimer dt = (DispatcherTimer)sender;
            dt.Stop();
        }

        void cancel_invisibility_bonus(object sender, EventArgs e)
        {
            invisibility = 1;
            draw(false, false, true, false);
            DispatcherTimer dt = (DispatcherTimer)sender;
            dt.Stop();
        }

        public void increase_damage(Bullet b)//API для увеличения повреждений
        {
            damage += 10;
            killer = b;
            refresh_damage();
        }

        Bullet killer;

        void refresh_damage()//обновляет сведения о танке в listbox
        {
            string s;
            ((App)Application.Current).Stat.Items.Clear();
            foreach (Tank t in ((App)Application.Current).Tanks)
            {
                s = string.Empty;
                s = t.Name + ": " + t.damage.ToString() + "%";
                ((App)Application.Current).Stat.Items.Add(s);
            }
            
            if (damage == 100)
            {
                refresh_frags();
                kill_tank(killer);
                
            }
        }

        void refresh_frags()
        {
            string s;
            ((App)Application.Current).Frags_list.Items.Clear();
            foreach (Tank t in ((App)Application.Current).Tanks)
            {
                s = string.Empty;
                s = t.Name + ": "+t.Frags.ToString();
                ((App)Application.Current).Frags_list.Items.Add(s);
            }
        }

        void check_GameOver()//проверяет, не выиграла ли команда после того, как убила танк противника
        {
            int cr = 0, cb = 0;
            foreach (Tank t in ((App)Application.Current).Tanks)
                if (t.Team == Colors.Red)
                    cr++;
                else
                    cb++;
            if (cb > 0 && cr > 0)
                return;
            Color c;
            if (cb == 0)
                c = Colors.Red;
            else
                c = Colors.Blue;
            ((App)Application.Current).MP.begin_new_game(c);
        }

        void kill_tank(Bullet b)//убивает танчик (когда поврежденя = 100%)
        {
            ((App)Application.Current).Main_canvas.Children.Remove(path);
            killer.Source_tank.Frags++;
            p = prepare_bang_polygon();
            ((App)Application.Current).Main_canvas.Children.Add(p);
            Canvas.SetLeft(p, position.X);
            Canvas.SetTop(p, position.Y);
            DispatcherTimer dt = new DispatcherTimer();
            dt.Tick += new EventHandler(hide_bang);
            dt.Interval = new TimeSpan(0, 0, 0, 0, 300);
            dt.Start();
        }
        Polygon p;

        void hide_bang(object sender, EventArgs e)
        {
            ((App)Application.Current).Tanks.Remove(this);
            ((App)Application.Current).Main_canvas.Children.Remove(p);
            ((DispatcherTimer)sender).Stop();
            check_GameOver();
        }

        Polygon prepare_bang_polygon()//подготавливает графику для взрыва
        {
            Polygon pol = new Polygon();
            pol.Height = 56;
            pol.Width = 54;
            PointCollection pc = new PointCollection();
            pc.Add(new Point(0, 28));
            pc.Add(new Point(18, 24));
            pc.Add(new Point(12, 12));
            pc.Add(new Point(24, 16));
            pc.Add(new Point(28, 0));
            pc.Add(new Point(32, 16));
            pc.Add(new Point(44, 12));
            pc.Add(new Point(38, 24));
            pc.Add(new Point(54, 28));
            pc.Add(new Point(38, 12));
            pc.Add(new Point(24, 24));
            pc.Add(new Point(32, 40));
            pc.Add(new Point(28, 56));
            pc.Add(new Point(24, 40));
            pc.Add(new Point(12, 24));
            pc.Add(new Point(18, 32));
            pol.Points = pc;
            ImageBrush im_br = new ImageBrush();
            im_br.ImageSource = new BitmapImage(new Uri("/Tanks;component/Images/bang.jpeg", UriKind.Relative));
            im_br.Stretch = Stretch.UniformToFill;
            pol.Fill = im_br;

            return pol;
        }
    }
}

